﻿#include "websocketclient.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QCryptographicHash>

WebSocketClient::WebSocketClient(QObject *parent) : QObject(parent), m_connected(false)
{
    // Connect WebSocket signals and slots
    connect(&m_webSocket, &QWebSocket::connected, this, &WebSocketClient::onConnected);
    connect(&m_webSocket, &QWebSocket::disconnected, this, &WebSocketClient::onDisconnected);
    connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocketClient::onTextMessageReceived);
    connect(&m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this,
            &WebSocketClient::onError);
}

WebSocketClient::~WebSocketClient()
{
    disconnectFromServer();
}

void WebSocketClient::connectToServer(const QString &url)
{
    if (m_webSocket.state() == QAbstractSocket::ConnectedState) {
        return;
    }

    m_webSocket.open(QUrl(url));
}

void WebSocketClient::disconnectFromServer()
{
    if (m_webSocket.state() != QAbstractSocket::UnconnectedState) {
        m_webSocket.close();
    }
}

void WebSocketClient::requestRtspUrl(const QString &cameraId)
{
    if (!m_connected) {
        emit errorOccurred(QString("WebSocket not connected"));
        return;
    }

    // Create request ID
    QString requestId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // Create JSON-RPC request
    QJsonObject request;
    request["id"] = requestId;
    request["method"] = "cameras.getStream";

    int32_t cameraIdInt = cameraId.toInt();
    QJsonObject params;
    params["channel"] = cameraIdInt;
    params["stream_type"] = 0;
    params["protocol"] = "rtsp";
    request["params"] = params;

    // Save request ID and camera ID mapping
    m_pendingRequests[requestId] = cameraId;

    // Send request
    QJsonDocument doc(request);
    m_webSocket.sendTextMessage(doc.toJson(QJsonDocument::Compact));
}

void WebSocketClient::sendMessage(const QString &message)
{
    if (!m_connected) {
        emit errorOccurred(QString("WebSocket not connected"));
        return;
    }

    m_webSocket.sendTextMessage(message);
}

bool WebSocketClient::isConnected() const
{
    return m_connected;
}

void WebSocketClient::onConnected()
{
    m_connected = true;
    emit connectionStateChanged(true);
}

void WebSocketClient::onDisconnected()
{
    m_connected = false;
    emit connectionStateChanged(false);
}

void WebSocketClient::onTextMessageReceived(const QString &message)
{
    // Send raw message signal
    emit textMessageReceived(message);

    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
    if (doc.isNull() || !doc.isObject()) {
        return;
    }

    QJsonObject obj = doc.object();

    // Check if it's a response message
    if (obj.contains("id") && obj.contains("result")) {
        QString id = obj["id"].toString();

        // Check if it's a pending request
        if (m_pendingRequests.contains(id)) {
            QString requestType = m_pendingRequests[id];
            QJsonObject result = obj["result"].toObject();

            // 处理不同类型的响应
            if (requestType == "challenge") {
                // 挑战码响应
                if (result.contains("challenge") && result.contains("expires_in")) {
                    QString challenge = result["challenge"].toString();
                    int expiresIn = result["expires_in"].toInt();
                    emit challengeReceived(challenge, expiresIn);
                }
            } else if (requestType == "login") {
                // 登录响应
                if (result.contains("access_token") && result.contains("refresh_token")) {
                    QString accessToken = result["access_token"].toString();
                    QString refreshToken = result["refresh_token"].toString();
                    QJsonObject userInfo = result.contains("user") ? result["user"].toObject() : QJsonObject();
                    emit loginSuccess(accessToken, refreshToken, userInfo);
                }
            } else if (requestType == "refreshToken") {
                // 刷新令牌响应
                if (result.contains("access_token")) {
                    QString accessToken = result["access_token"].toString();
                    QString refreshToken = result.contains("refresh_token") ? result["refresh_token"].toString() : "";
                    QJsonObject emptyObj;
                    emit loginSuccess(accessToken, refreshToken, emptyObj);
                }
            } else if (result.contains("url")) {
                // RTSP URL响应
                QString url = result["url"].toString();
                QString expiresAt = result.contains("expires_at") ? result["expires_at"].toString() : "";

                // Send RTSP URL signal
                emit rtspUrlReceived(url, expiresAt);
            }

            // Remove pending request
            m_pendingRequests.remove(id);
        }
    }
    // Check if it's an error message
    else if (obj.contains("id") && obj.contains("error")) {
        QString id = obj["id"].toString();
        QJsonObject error = obj["error"].toObject();

        int errorCode = error.contains("code") ? error["code"].toInt() : 0;
        QString errorMessage = error.contains("message") ? error["message"].toString() : QString("Unknown error");

        // 如果是登录相关请求的错误，发送登录失败信号
        if (m_pendingRequests.contains(id)) {
            QString requestType = m_pendingRequests[id];
            if (requestType == "challenge" || requestType == "login" || requestType == "refreshToken") {
                emit loginFailed(errorCode, errorMessage);
            } else {
                emit errorOccurred(errorMessage);
            }
        } else {
            emit errorOccurred(errorMessage);
        }

        // Remove pending request
        if (m_pendingRequests.contains(id)) {
            m_pendingRequests.remove(id);
        }
    }
}

void WebSocketClient::onError(QAbstractSocket::SocketError error)
{
    Q_UNUSED(error);
    emit errorOccurred(QString("WebSocket error: ") + m_webSocket.errorString());
}

void WebSocketClient::requestChallenge(const QString &username, const QString &deviceId)
{
    if (!m_connected) {
        emit errorOccurred("未连接到服务器");
        return;
    }

    // 创建请求ID
    QString requestId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // 创建请求JSON对象
    QJsonObject requestObj;
    requestObj["id"] = requestId;
    requestObj["method"] = "auth.getChallenge";

    QJsonObject paramsObj;
    paramsObj["username"] = username;
    paramsObj["device_id"] = deviceId;
    requestObj["params"] = paramsObj;

    // 转换为JSON文档
    QJsonDocument doc(requestObj);
    QString message = doc.toJson(QJsonDocument::Compact);

    // 记录这是一个挑战码请求
    m_pendingRequests[requestId] = "challenge";

    // 发送请求
    m_webSocket.sendTextMessage(message);
}

void WebSocketClient::login(const QString &username,
                            const QString &challenge,
                            const QString &credential,
                            const QString &deviceId,
                            bool rememberMe)
{
    if (!m_connected) {
        emit errorOccurred("未连接到服务器");
        return;
    }

    // 创建请求ID
    QString requestId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // 创建请求JSON对象
    QJsonObject requestObj;
    requestObj["id"] = requestId;
    requestObj["method"] = "auth.login";

    QJsonObject paramsObj;
    paramsObj["username"] = username;
    paramsObj["challenge"] = challenge;
    paramsObj["credential"] = credential;
    paramsObj["device_id"] = deviceId;

    // 设备信息
    QJsonObject deviceInfoObj;
    deviceInfoObj["type"] = "desktop";
    deviceInfoObj["os"] = "Windows";
    deviceInfoObj["client"] = "Open IPC PC Client";
    paramsObj["device_info"] = deviceInfoObj;

    paramsObj["remember_me"] = rememberMe;

    requestObj["params"] = paramsObj;

    // 转换为JSON文档
    QJsonDocument doc(requestObj);
    QString message = doc.toJson(QJsonDocument::Compact);

    // 记录这是一个登录请求
    m_pendingRequests[requestId] = "login";

    // 发送请求
    m_webSocket.sendTextMessage(message);
}

void WebSocketClient::refreshToken(const QString &refreshToken, const QString &deviceId)
{
    if (!m_connected) {
        emit errorOccurred("未连接到服务器");
        return;
    }

    // 创建请求ID
    QString requestId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // 创建请求JSON对象
    QJsonObject requestObj;
    requestObj["id"] = requestId;
    requestObj["method"] = "auth.refreshToken";

    QJsonObject paramsObj;
    paramsObj["refresh_token"] = refreshToken;
    paramsObj["device_id"] = deviceId;
    requestObj["params"] = paramsObj;

    // 转换为JSON文档
    QJsonDocument doc(requestObj);
    QString message = doc.toJson(QJsonDocument::Compact);

    // 记录这是一个刷新令牌请求
    m_pendingRequests[requestId] = "refreshToken";

    // 发送请求
    m_webSocket.sendTextMessage(message);
}

void WebSocketClient::logout(const QString &deviceId, bool logoutAll)
{
    if (!m_connected) {
        emit errorOccurred("未连接到服务器");
        return;
    }

    // 创建请求ID
    QString requestId = QUuid::createUuid().toString(QUuid::WithoutBraces);

    // 创建请求JSON对象
    QJsonObject requestObj;
    requestObj["id"] = requestId;
    requestObj["method"] = "auth.logout";

    QJsonObject paramsObj;
    paramsObj["device_id"] = deviceId;
    paramsObj["logout_all"] = logoutAll;
    requestObj["params"] = paramsObj;

    // 转换为JSON文档
    QJsonDocument doc(requestObj);
    QString message = doc.toJson(QJsonDocument::Compact);

    // 记录这是一个登出请求
    m_pendingRequests[requestId] = "logout";

    // 发送请求
    m_webSocket.sendTextMessage(message);
}